package file_update

import (
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
)

/**
 * Go 上传文件
 * 上传的文件经过 Go 的解析保存在 *http.Request.MultipartForm 中,通过 r.FormFile() 去获取收到的文件信息和数据流，并处理
 */

/**
 * 普通的post表单请求，Content-Type=application/x-www-form-urlencoded
 * 有文件上传的表单，  Content-Type=multipart/form-data
 *
 * Form：    存储了 post、put和get 参数，在使用之前需要调用 ParseForm 方法。
 * PostForm：存储了 post、put      参数，在使用之前需要调用 ParseForm 方法。
 * MultipartForm：存储了包含了文件上传的表单的 post 参数，在使用前需要调用 ParseMultipartForm 方法。
 */

func FileUpdate() {

	//上传页
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		//如果请求是 get 就是加载模板文件，否则为上传文件
		if r.Method == "GET" {

			//加载模板文件
			t, _ := template.ParseFiles("./http/file_update/file_update.html")
			//输出模板内容
			t.Execute(w, nil)

			return
		}

		// 这里一定要记得 r.ParseMultipartForm(), 否则 r.MultipartForm 是空的
		// 调用 r.FormFile() 的时候会自动执行 r.ParseMultipartForm()
		// 写明缓冲的大小。如果超过缓冲，文件内容会被放在临时目录中，而不是内存。过大可能较多占用内存，过小可能增加硬盘 I/O
		// FormFile() 时调用 ParseMultipartForm() 使用的大小是 32 << 20，32MB
		r.ParseMultipartForm(1 << 15)
		file, handler, err := r.FormFile("upname") // upname 是上传表单域的名字
		if err != nil {
			log.Println("上传错误:", err)
			return
		}
		defer file.Close()// 此时上传内容的 IO 已经打开，需要手动关闭！！

		//上传文件的文件名
		filename := handler.Filename

		// 打开一个文件
		// os.O_CREATE 表示文件不存在就会创建
		// os.O_APPEND 表示以追加内容的形式添加
		// os.O_WRONLY 表示只写模式
		// os.O_RDONLY 表示只读模式
		// os.O_RDWR 表示读写模式
		f, _ := os.OpenFile("./static/"+filename, os.O_CREATE|os.O_WRONLY, 0660)
		defer f.Close()

		//将上传输入流复制到文件里面
		_, err = io.Copy(f, file)
		if err != nil {
			log.Println("上传失败")
			return
		}

		w.Write([]byte("上传完成：" + filename))
	})

	//设置访问的路由
	http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
		http.FileServer(http.Dir("./static/")).ServeHTTP(w, r)
	})

	//设置监听的端口
	err := http.ListenAndServe(":80", nil)
	if err != nil {
		log.Fatal("监听端口失败: ", err)
	}

}
